package com.sf.guava.stream;

import com.google.common.base.Strings;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;

/**
 * @Classname StreamTest
 * @Description jdk1.8 新增的 stream 的使用
 * Java 8引入了全新的Stream API。这里的Stream和I/O流不同，它更像具有Iterable的集合类，但行为和集合类又有所不同。
 * 优势
 *  1.增强对集合功能的操作
 *  2.函数式编程，代码已读，可维护性好，业务逻辑清楚
 *  3.大气高端 上档次
 * @Date 2019/12/16 0016 19:47
 * @Created by 埔枘
 */
public class StreamTest {

    /**
     *  获取第一个值
     *  如果 stream 没有顺序 那么都有可能返回
     *  如果所选元素 为 空  那么 抛出 NullPointException
     */
    public static void getFirstValue(){
        List<Integer> list1 = getList();
        Optional<Integer> first = list1.stream().findFirst();
        System.out.println(first);
    }

    /**
     *  去重复
     */
    public static void distinctTest(){
        List<Integer> list = getList();
        List<Integer> list1 = list.stream().distinct().collect(toList());
        System.out.println(list1);
    }


    /**
     *  获取任意 元素
     *  如果流为空，则为空
     */
    public static void findAnyTest(){
        List<Integer> list1 = getList();
        Optional<Integer> any = list1.stream().findAny();
        System.out.println(any);
    }

    /**
     *  过滤器
     */
    public static void filterTest(){
        List<Integer> list1 = getList();
        List list = list1.stream().filter(str->{
            if(1 == str||2 == str){
                return true;
            }
            return false;
        }).collect(toList());
        System.out.println(list);
    }

    /**
     *  生成 一对一的值
     *
     */
    public static void mapTest(){
        List<Integer> list1 = getList();
        List<Integer> collect = list1.stream().map(str -> str + 1).collect(toList());
        System.out.println(collect);
    }

    /**
     *  相对 Map 更深层次
     */
    public static void flatMapTest(){
        List<Person> personList = getPeopleList();

        // 深层次的循环
        // flatMap可以操作对象里面的对象，而map只能操作第一层。
        // 如果入参的是对象，那么 flatMap 可以操作到对象的属性，而map 只能操作到 对象
        // 及早求值
        List resultList1 = personList.stream()
                .flatMap(person -> Arrays.stream(person.getName().split(" "))).collect(toList());
        //打印姓名
        System.out.println(resultList1);

        // 对比 map  惰性求值
        List<Stream<String>> resultList2 = personList.stream()
                .map(person -> Arrays.stream(person.getName().split(" "))).collect(toList());
        // 打印 Stream 对象 地址
        System.out.println(resultList2);
    }


    /**
     *  累加测试
     */
    public static void reduceTest(){
        List<Integer> arr = getList();
        // 累加
        Integer reduce1 = arr.stream().reduce(10, (sun, item) -> {
            return sun + item;
        });
        //简写
        Integer reduce2 = arr.stream().reduce(10, (sun, item) ->sun + item);

        // 字符串累加 拼接
        String reduce3 = Stream.of("1", "2", "3")
                .reduce("0", (x, y) -> (x + "," + y));
        System.out.println(reduce2);

        // 打印 17
        System.out.println(reduce1);
        System.out.println(reduce2);
        System.out.println(reduce3);
    }
    /**
     *  以下演示 Collect 的相关用法
     *
     * 1 toList()
     *
     * 2、toSet()
     *
     * 3、toMap()
     *
     * 4、自定义
     */

    public static void toListTest(){
        List<Double> collect = getList().stream().map(Integer::doubleValue).collect(toList());
        //打印 [1.0, 3.0, 1.0, 2.0]
        System.out.println(collect);
    }
    public static void toSetTest(){
        Set<Double> collect = getList().stream().map(Integer::doubleValue).collect(toSet());
        //打印 [1.0, 2.0, 3.0]   自动去重复
        System.out.println(collect);
    }
    public static void toMapTest(){
        List<Person> personList = getPeopleList();
        Map<String, Integer> collect = personList.stream().collect(toMap(Person::getName, Person::getAge));
        //打印 {zhang2=3, zhang3=4, zhang0=1, zhang1=2, zhang8=9, zhang9=10, zhang6=7, zhang7=8, zhang4=5, zhang5=6}   乱序
        System.out.println(collect);
    }

    /**
     * 转换成 指定类型
     */
    public static void toTreeSetTest(){
        List<Integer> list = getList();
        TreeSet collect = list.stream()
                .collect(Collectors.toCollection(TreeSet::new));
        System.out.println(collect);
    }

    /**
     * 分组
     */
    public static void toGroupTest(){
        List<Person> data = getPeopleList();
        Map<Boolean, List<Person>> collect = data.stream()
                .collect(Collectors.groupingBy(person -> person.getAge()>5));

        Iterator<Map.Entry<Boolean, List<Person>>> iterator = collect.entrySet().iterator();

        while(iterator.hasNext()){
            Map.Entry<Boolean, List<Person>> next = iterator.next();
            List<Person> personList = next.getValue();
            if(next.getKey() == true){
                personList.forEach(person->System.out.println(Strings.lenientFormat("年龄 5岁以上的-姓名: %s",person.getName())));
            }else{
                personList.forEach(person->System.out.println(Strings.lenientFormat("年龄 5岁以下的-姓名: %s",person.getName())));
            }
        }
    }


    /**
     * 分隔
     */
    public static void toJoiningTest(){
        List<Person> peopleList = getPeopleList();
        String collect = peopleList.stream()
                .map(person -> person.getName())
                //以 , 分割 前后缀分别为 {  }
                .collect(Collectors.joining(",", "{", "}"));
        System.out.println(collect);
    }


    /**
     *  累加
     */
    public static void toReduceTest(){
        List collect = Stream.of("1", "2", "3","4").collect(
                Collectors.reducing(new ArrayList(), x -> Arrays.asList(x), (y, z) -> {
                    y.addAll(z);
                    return y;
                }));
        System.out.println(collect);
    }


    /**
     *  并发
     */
    public static void paralleList(){
        int size = 10;
        List<Integer> list = new ArrayList<>(size);
        for (Integer i = 0; i < size; i++) {
            list.add(new Integer(i));
        }

        List<Integer> temp1 = new ArrayList<>(size);
        //老的
        long start=System.currentTimeMillis();
        for (Integer i: list) {
            temp1.add(i);
        }
        System.out.println(+System.currentTimeMillis()-start);

        //同步
        long start1=System.currentTimeMillis();
        list.stream().collect(Collectors.toList());
        System.out.println(System.currentTimeMillis()-start1);

        //并发
        long start2=System.currentTimeMillis();
        list.parallelStream().collect(Collectors.toList());
        System.out.println(System.currentTimeMillis()-start2);
    }

    /**
     *  线程安全问题
     */
    public static void paralleSafety(){
        List<Integer> list1 = new ArrayList<Integer>();
        List<Integer> list2 = new ArrayList<Integer>();
        List<Integer> list3 = new ArrayList<Integer>();
        List<Integer> list4 = new CopyOnWriteArrayList<Integer>();

        long millis = System.currentTimeMillis();
        IntStream.range(0,1000).forEach(list1::add);
        long endMillis = System.currentTimeMillis();
//        System.out.println(endMillis-millis);

        //线程不安全
//        IntStream.range(0,1000).parallel().forEach(list2::add);
        IntStream.range(0,1000).parallel().forEach(list4::add);

        long millis1 = System.currentTimeMillis();
        Lock lock = new ReentrantLock();
        IntStream.range(0, 1000).parallel().forEach(i -> {
            lock.lock();
            try {
                list3.add(i);
            }finally {
                lock.unlock();
            }
        });
        long endMillis1 = System.currentTimeMillis();
//        System.out.println(endMillis1-millis1);

        System.out.println(list1.size());
        System.out.println(list2.size());
        System.out.println(list3.size());
        System.out.println(list4.size());
    }

    /**
     *  调试
     *  .
     *  使用 peek 打印值
     */
    public static void debugTest(){
        List<Integer> list = getList();
        List<Long> collect = list.stream().map(value -> value.longValue()).peek(v -> {
            System.out.println(v == 10);
        }).collect(toList());

        System.out.println(collect);
    }


    public static void main(String[] args) {
        paralleSafety();
    }

    private static List<Integer> getList() {
        List<Integer> arrayList = new ArrayList();
        arrayList.add(1);
        arrayList.add(3);
        arrayList.add(1);
        arrayList.add(2);
        return arrayList;
    }

    private static List<Person> getPeopleList() {
        List<Person> personList = new ArrayList();
        for(int i=0;i<10;i++){
            Person person1 = new Person();
            person1.setAge(1+i);
            person1.setName("zhang"+i);
            personList.add(person1);
        }
        return personList;
    }



}

class Person{
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
